/*
 * =====================================================================================
 *
 *       Filename:  This experiment initialize a big memory array to keep
 *       track of of Binary decision diagram. See the main file for more
 *       detail.
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  Friday 05 August 2011 09:15:40  IST
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Dilawar Singh (Graduate Student, EE IITB), dilawar@ee.iitb.ac.in
 *      Institute:  IIT Bombay
 *
 * =====================================================================================
 */


#include	<stdio.h>
#include	<stdlib.h>
#include	<gb_flip.h>

#define o mems++ 
#define oo mems+=2
#define ooo mems+=3
#define oooo mems+=4
#define addr_(p) ((addr)(size_t)(p))
#define bddNode_(a) ((bddNode*)(size_t)(a))
#define page_(a) ((page*)(size_t)(a))


#define logPageSize 12
#define memSize (1<<29)
#define pageSize (1<<logPageSize)
#define pageInts (pageSize/sizeof(int))
#define pageMask (pageSize-1)
#define topOfMem ((page*)&mem[memSize])

#define PRINT_BDDNODE(myNode)  \
        printf("|- bddNode* " #myNode "(%d)\n", (int)myNode); \
        if(myNode != NULL) {\
            printf("\t|- "#myNode"->varRef (%d)\n", (int)myNode->varRef);\
            printf("\t|- "#myNode"->lo (%d)\n", (int)myNode->lo);\
            printf("\t|- "#myNode"->hi (%d)\n", (int)myNode->hi);\
        }\
        else \
        {\
            printf("\t|- NULL! No other member can be found!\n");\
        }

        
typedef unsigned int addr;

typedef struct nodeStruct {
  addr lo,hi;
  int varRef; /* reference count minus one */
  unsigned int index; /* variable ID followed by random bits */
} bddNode;

typedef struct pageStruct {
  addr dat[pageInts];
} page;  

bddNode *botSink, *topSink;
bddNode *pNode;
page *pPage;

long long mems = 9999, rmems, zmems;
char mem[200];

bddNode *pBddNode;   /* the smallest unused node in mem */
page *pPage;         /* the smallest used page in mem */
bddNode *pNodeAvail; /* stack of node available for reuse */
page *pPageAvail;    /* stack of page available for reuse */
bddNode *botSink, *topSink; /* the sink nodes. They never go away. */
int totalNodes;      /* This many nodes are currently in use. */
int deadNodes;       /* and this many of them currently have [[varRef<0]] */
int extraLife = 10;  /* I ll try ten times before dying. */


/*  function def */
bddNode* reserveNode(void);
void showStats();

int main()
{
    /* Check if long long has the required size. */

    if (sizeof(long long) != 8)
    {
        fprintf(stderr, "Sorry, I assume that sizeof(long long) is 8!\n");
        exit(-2);
    }
    
    /* Checking sizes */
    printf("Checking sizes\n");
    printf("|- lo and hi sizes are : %d\n", sizeof(addr));
    printf("|- varRef size is : %d\n", sizeof(int));
    printf("|- bddNode size is : %d\n", sizeof(bddNode));
    printf("|- page size is : %d\n", sizeof(page));
    printf("|- memSize %d\n", memSize);
    printf("|- mems : %lld\n", mems);
    printf("|- mems1 : %lld\n", mems);
    printf("|- botSink and topSink : %d, %d\n", (int)addr_(botSink), (int)addr_(topSink));


    printf("\nChecking initial values\n");
    printf("|- pNodeAvail : %d\n", (int)pNodeAvail);
    printf("|- pPageAvail : %d\n", (int)pPageAvail);

    /*
     * Intialise everything.
     */

    botSink = (bddNode *) mem;    /*sink node for the all-zero function */
    topSink = botSink + 1;     /* sink node of all-one function. */
    o, botSink->lo = botSink->hi = addr_(botSink);
    o, topSink->lo = topSink->hi = addr_(topSink);
    oo, botSink->varRef = topSink->varRef = 0;
    o, botSink -> lo=botSink -> hi=addr_(botSink);
    oooo, botSink->index = gb_next_rand(); /* use Stanford graph base */
    oooo, topSink->index = gb_next_rand();
    totalNodes = 2;
    pBddNode = topSink + 1;
    pPage = topOfMem;
    /*  END Initialization */
    
        /*  some test cases */
    bddNode* testNode;
    int loop = 0;
    for (loop = 0; loop < 10; loop++)
    {
        testNode = reserveNode();
        //printf("|-- testNode->varRef: %d, testNode->lo %d\n", (int)testNode->varRef, (int)testNode->lo);
    }
    return 0;
}


bddNode* reserveNode(void)
{
    printf("We are in the reserveNode function.\n");
    
    /*  initialize a node r */
    register bddNode *r = pNodeAvail;
    printf("New node r is %d (%d) \n", (int)r, (int)pNodeAvail);
    if (r != 0)
    {
#ifdef  DEBUG
        PRINT_BDDNODE(pNodeAvail);
#endif 
        o, pNodeAvail = bddNode_(pNodeAvail->varRef);
#ifdef  DEBUG
        printf("After binding to varref, pNodeAvail %d", pNodeAvail);
        PRINT_BDDNODE(pNodeAvail);
#endif 

    }
    else
    {
#ifdef  DEBUG
        PRINT_BDDNODE(r);
        printf("|- r : %d pBddNode : %d \n", (int)r, (int)pBddNode);
        printf("|- pNodeAvail %d\n", (int)pNodeAvail);
#endif     /* -----  not DEBUG  ----- */
        r = pBddNode;
        if ( r < (bddNode*)pPage)
        {
            printf("\t|-: r (%d) is less than pPage (%d)\n", r, pPage);
            pBddNode++;
        }
        else
        {
            extraLife--;
#ifdef  DEBUG
            fprintf(stderr, "NULL node forced (%d pages, %d nodes, %d dead\n)", topOfMem - pPage, pBddNode - botSink, deadNodes);
#endif     /* -----  not DEBUG  ----- */
            if( extraLife == 0)
            {
                showStats();
                exit(-98); /* sigh */
            }
            return NULL;
        }
    }
    totalNodes++;
    return r;
}


void showStats()
{
    printf("In showstats.");
}


void printStruct(bddNode* a)
{

}
